package com.qzsoft.zhjd.common.utils;

import com.alibaba.fastjson.JSON;
import com.qzsoft.zhjd.common.enums.DeviceType;
import com.qzsoft.zhjd.common.model.BurnFurnaceData;
import com.qzsoft.zhjd.common.model.DuctilityData;
import com.qzsoft.zhjd.common.model.InstrumentData;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
 * 北京中科建仪电子科技有限公司
 * 沥青针入度仪,沥青软化点仪,沥青混合料马歇尔稳定度试验仪 通用工具类
 *
 * 主要功能：
 * 1. 解析针入度仪、软化点仪、马歇尔稳定度试验仪的数据协议
 * 2. 解析燃烧法沥青含量测定仪和低温延度仪的数据协议
 */
public class AsphaltProtocolParserUtils {

    // ==================== 通用常量定义 ====================

    private static final byte[] HEADER = {(byte) 0xFA, (byte) 0xFB, (byte) 0xFC};
    public static final byte TYPE_REALTIME = (byte) 0xA4; // 试验数据
    public static final byte TYPE_RESULT = (byte) 0xA7;   // 试验结果数据

    private static final byte START_BYTE = 0x02;
    private static final byte CONNECTION_TYPE = 0x55;
    private static final byte END_BYTE = 0x0A;

    // 设备类型标识
    private static final byte[] DEVICE_BURN_FURNACE = {0x00, 0x00}; // 燃烧炉
    private static final byte[] DEVICE_DUCTILITY = {0x00, 0x01};    // 延伸仪

    // ==================== 针入度仪、软化点仪、马歇尔稳定度试验仪解析方法 ====================

    /**
     * 从十六进制字符串解析一帧数据（针入度仪、软化点仪、马歇尔稳定度试验仪）
     * 示例输入: "0xFA 0xFB 0xFC 0x07 0xA4 01 09C4 01F4 0x5F"
     *
     * @param hex 十六进制字符串
     * @param deviceType 设备类型
     * @return 解析结果
     */
    public static ParsedResult parseHexString(String hex, String deviceType) {
        if (hex == null || hex.trim().isEmpty()) {
            return null;
        }

        hex = hex.replaceAll("0x", "").replaceAll(" ", "");
        if (hex.length() % 2 != 0) throw new IllegalArgumentException("Odd hex length");
        byte[] frame = new byte[hex.length() / 2];
        for (int i = 0; i < frame.length; i++) {
            frame[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
        }

        return parseFrame(frame, deviceType);
    }

    /**
     * 解析字节数组帧（针入度仪、软化点仪、马歇尔稳定度试验仪）
     *
     * @param frame 字节数组帧
     * @param dType 设备类型
     * @return 解析结果
     */
    private static ParsedResult parseFrame(byte[] frame, String dType) {
        if (frame.length < 7) return null;

        // 校验帧头
        for (int i = 0; i < 3; i++) {
            if (frame[i] != HEADER[i]) return null;
        }

        int dataLen = frame[3] & 0xFF;
        byte dataType = frame[4];
        //试验数据和结果数据返回的字段长度不同，针织仪和马歇尔传的参数长度一致
        if ((frame.length != 4 + dataLen) && (frame.length != 3 + dataLen) ){
            return null;
        }
        // 校验和验证
        int sum = 0;
        for (int i = 0; i < frame.length - 1; i++) {
            sum += frame[i] & 0xFF;
        }
        if ((sum & 0xFF) != (frame[frame.length - 1] & 0xFF)) {
            return null;
        }

        // 判断设备类型
        DeviceType deviceType;
        if ((dataType == TYPE_REALTIME && dataLen == 7) || (dataType == TYPE_RESULT && dataLen == 6)) {
            deviceType = dType.equals(DeviceType.PENETRATION_BJZKJYDZ.name()) ? DeviceType.PENETRATION_BJZKJYDZ :
                    DeviceType.MARSHALL_BJZKJYDZ; // 或 MARSHALL，此处需业务判断
        } else if ((dataType == TYPE_REALTIME && dataLen == 11) || (dataType == TYPE_RESULT && dataLen == 10)) {
            deviceType = DeviceType.SOFTENING_POINT_BJZKJYDZ;
        } else {
            return null;
        }

        ParsedResult result = new ParsedResult();
        result.deviceType = deviceType;
        result.dataType = dataType;

        int idx = 5;
        if (deviceType == DeviceType.SOFTENING_POINT_BJZKJYDZ) {
            // 软化点仪数据解析
            if (dataType == TYPE_REALTIME) {
                result.flag = frame[idx++] & 0xFF;
            }
            result.min = BigDecimal.valueOf(frame[idx++] & 0xFF);
            result.sec = BigDecimal.valueOf(frame[idx++] & 0xFF);
            result.num1 = BigDecimal.valueOf(frame[idx++] & 0xFF);
            result.dt1 = BigDecimal.valueOf(readSignedShort(frame, idx));
            idx += 2;
            result.num2 = BigDecimal.valueOf(frame[idx++] & 0xFF);
            result.dt2 = BigDecimal.valueOf(readSignedShort(frame, idx));
        } else {
            // 针入度仪 or 马歇尔稳定度试验仪数据解析
            if (dataType == TYPE_REALTIME) {
                result.flag = frame[idx++] & 0xFF;
            }
            result.dpOrDs = BigDecimal.valueOf(readUnsignedShort(frame, idx));
            idx += 2;
            result.dtOrDf = BigDecimal.valueOf(readSignedShort(frame, idx));
        }

        return result;
    }

    /**
     * 读取无符号短整型
     */
    private static int readUnsignedShort(byte[] data, int offset) {
        return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
    }

    /**
     * 读取有符号短整型
     */
    private static int readSignedShort(byte[] data, int offset) {
        int val = ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
        return (val >= 0x8000) ? val - 0x10000 : val;
    }

    // ==================== 燃烧法沥青含量测定仪和低温延度仪解析方法 ====================

    /**
     * 燃烧法沥青含量测定仪和低温延度仪通用解析方法
     *
     * @param hexString 十六进制字符串
     * @return 仪器数据
     */
    public static InstrumentData parseDataFrame(String hexString) {
        byte[] frame = hexStringToByteArray(hexString);
        return parseDataFrame(frame);
    }

    /**
     * 解析仪器数据帧（燃烧炉和延伸仪）
     *
     * @param frame 字节数组帧
     * @return 仪器数据
     */
    public static InstrumentData parseDataFrame(byte[] frame) {
        if (!validateFrame(frame)) {
            throw new IllegalArgumentException("无效的数据帧格式");
        }

        // 解析设备类型
        byte[] deviceTypeBytes = {frame[2], frame[3]};
        InstrumentData result;

        if (Arrays.equals(deviceTypeBytes, DEVICE_BURN_FURNACE)) {
            result = parseBurnFurnaceData(frame);
        } else if (Arrays.equals(deviceTypeBytes, DEVICE_DUCTILITY)) {
            result = parseDuctilityData(frame);
        } else {
            throw new IllegalArgumentException("未知的设备类型: " +
                    String.format("%02X %02X", deviceTypeBytes[0], deviceTypeBytes[1]));
        }

        return result;
    }

    /**
     * 验证数据帧基本格式
     */
    private static boolean validateFrame(byte[] frame) {
        if (frame == null || frame.length < 10) {
            return false;
        }

        // 检查起始字节、连接类型和结束字节
        return frame[0] == START_BYTE &&
                frame[1] == CONNECTION_TYPE &&
                frame[frame.length - 1] == END_BYTE;
    }

    // ==================== 燃烧炉数据解析方法 ====================

    /**
     * 解析燃烧炉数据
     */
    private static BurnFurnaceData parseBurnFurnaceData(byte[] frame) {
        BurnFurnaceData data = new BurnFurnaceData();
        data.setDeviceType("燃烧炉");

        // 解析数据长度 (第5-6字节)
        int dataLength = hexAsciiToInt(new byte[]{frame[4], frame[5]});
        data.setDataLength(dataLength);

        int dataStartIndex = 6;

        // 解析皮重 (6字节)
        data.setTareWeight(parseWeight(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 6)));
        dataStartIndex += 6;

        // 解析料重 (6字节)
        data.setMaterialWeight(parseWeight(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 6)));
        dataStartIndex += 6;

        // 解析当前重量 (6字节)
        data.setCurrentWeight(parseWeight(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 6)));
        dataStartIndex += 6;

        // 解析温度 (4字节)
        data.setTemperature(hexAsciiToInt(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 4)));
        dataStartIndex += 4;

        // 解析仪器状态 (2字节)
        data.setStatus(parseStatus(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 2)));
        dataStartIndex += 2;

        // 解析年月日期 (12字节)
        data.setDateTime(parseDateTime(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 12)));
        dataStartIndex += 12;

        // 解析试验材料类型 (2字节)
        data.setMaterialType(parseMaterialType(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 2)));
        dataStartIndex += 2;

        // 解析修正系数 (2字节)
        data.setCorrectionFactor(parseCorrectionFactor(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 2)));
        dataStartIndex += 2;

        // 解析试验时间 (4字节)
        data.setTestDuration(hexAsciiToInt(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 4)));
        dataStartIndex += 4;

        // 解析验证码 (4字节)
        data.setChecksum(bytesToHexString(Arrays.copyOfRange(frame, dataStartIndex, dataStartIndex + 4)));

        return data;
    }

    // ==================== 延伸仪数据解析方法 ====================

    /**
     * 解析延伸仪数据
     */
    /**
     * 解析延伸仪数据
     */
    /**
     * 解析延伸仪数据 - 最终修正版本
     */
    /**
     * 解析延伸仪数据 - 修正字节索引版本
     */
    private static DuctilityData parseDuctilityData(byte[] frame) {
        DuctilityData data = new DuctilityData();
        data.setDeviceType("延伸仪");

        try {
            // 解析数据长度 (第5-6字节)
            int dataLength = hexAsciiToInt(new byte[]{frame[4], frame[5]});
            data.setDataLength(dataLength);

            // 数据开始位置：帧头(1) + 连接类型(1) + 设备类型(2) + 数据长度(2) = 6
            int index = 6;

            // 调试：打印整个数据帧
//            System.out.println("完整数据帧: " + bytesToHexString(frame));
//            System.out.println("数据长度: " + dataLength);

            // 数据1 (4字节)
            byte[] data1Bytes = Arrays.copyOfRange(frame, index, index + 4);
//            System.out.println("数据1 [" + index + "-" + (index+3) + "]: " +
//                    bytesToHexString(data1Bytes) + " -> '" +
//                    new String(data1Bytes) + "'");
            data.setData1(hexAsciiToInt(data1Bytes));
            index += 4;

            // 电机速度 (2字节)
            byte[] motorBytes = Arrays.copyOfRange(frame, index, index + 2);
//            System.out.println("电机速度 [" + index + "-" + (index+1) + "]: " +
//                    bytesToHexString(motorBytes) + " -> '" +
//                    new String(motorBytes) + "'");
            data.setMotorSpeed(hexAsciiToInt(motorBytes));
            index += 2;

            // 数据2 (4字节)
            byte[] data2Bytes = Arrays.copyOfRange(frame, index, index + 4);
//            System.out.println("数据2 [" + index + "-" + (index+3) + "]: " +
//                    bytesToHexString(data2Bytes) + " -> '" +
//                    new String(data2Bytes) + "'");
            data.setData2(hexAsciiToInt(data2Bytes));
            index += 4;

            // 跳过空字节 (2字节)
            byte[] empty1Bytes = Arrays.copyOfRange(frame, index, index + 2);
//            System.out.println("空字节1 [" + index + "-" + (index+1) + "]: " +
//                    bytesToHexString(empty1Bytes) + " -> '" +
//                    new String(empty1Bytes) + "'");
            index += 2;

            // 数据3 (4字节)
            byte[] data3Bytes = Arrays.copyOfRange(frame, index, index + 4);
//            System.out.println("数据3 [" + index + "-" + (index+3) + "]: " +
//                    bytesToHexString(data3Bytes) + " -> '" +
//                    new String(data3Bytes) + "'");
            data.setData3(hexAsciiToInt(data3Bytes));
            index += 4;

            // 跳过空字节 (2字节)
            byte[] empty2Bytes = Arrays.copyOfRange(frame, index, index + 2);
//            System.out.println("空字节2 [" + index + "-" + (index+1) + "]: " +
//                    bytesToHexString(empty2Bytes) + " -> '" +
//                    new String(empty2Bytes) + "'");
            index += 2;

            // 温度 (4字节)
            byte[] tempBytes = Arrays.copyOfRange(frame, index, index + 4);
//            System.out.println("温度 [" + index + "-" + (index+3) + "]: " +
//                    bytesToHexString(tempBytes) + " -> '" +
//                    new String(tempBytes) + "'");
            data.setTemperature(hexAsciiToInt(tempBytes));
            index += 4;

            // 状态 (2字节)
            byte[] statusBytes = Arrays.copyOfRange(frame, index, index + 2);
//            System.out.println("状态 [" + index + "-" + (index+1) + "]: " +
//                    bytesToHexString(statusBytes) + " -> '" +
//                    new String(statusBytes) + "'");
            int statusValue = hexAsciiToInt(statusBytes);
            data.setStatus(statusValue == 0 ? "非试验状态" : "试验状态");
            index += 2;

            // 年月日期 (12字节)
            byte[] dateBytes = Arrays.copyOfRange(frame, index, index + 12);
//            System.out.println("日期时间 [" + index + "-" + (index+11) + "]: " +
//                    bytesToHexString(dateBytes) + " -> '" +
//                    new String(dateBytes) + "'");
            String dateTimeStr = new String(dateBytes, StandardCharsets.US_ASCII);
            // 格式化为可读日期
            if (dateTimeStr.matches("\\d{12}")) {
                String formattedDateTime = String.format("%s年%s月%s日 %s时%s分",
                        dateTimeStr.substring(0, 4),   // 年
                        dateTimeStr.substring(4, 6),   // 月
                        dateTimeStr.substring(6, 8),   // 日
                        dateTimeStr.substring(8, 10),  // 时
                        dateTimeStr.substring(10, 12)); // 分
                data.setDateTime(formattedDateTime);
            } else {
                data.setDateTime(dateTimeStr);
            }
            index += 12;

            // 跳过空字节 (8字节)
            byte[] empty3Bytes = Arrays.copyOfRange(frame, index, index + 8);
//            System.out.println("空字节3 [" + index + "-" + (index+7) + "]: " +
//                    bytesToHexString(empty3Bytes) + " -> '" +
//                    new String(empty3Bytes) + "'");
            index += 8;

            // 验证码 (4字节)
            byte[] checksumBytes = Arrays.copyOfRange(frame, index, index + 4);
//            System.out.println("验证码 [" + index + "-" + (index+3) + "]: " +
//                    bytesToHexString(checksumBytes) + " -> '" +
//                    new String(checksumBytes) + "'");
            data.setChecksum(bytesToHexString(checksumBytes));

//            System.out.println("解析完成，最终索引: " + (index + 4) + ", 帧总长度: " + frame.length);

        } catch (Exception e) {
            throw new IllegalArgumentException("解析延伸仪数据时出错: " + e.getMessage(), e);
        }

        return data;
    }

    // ==================== 通用工具方法 ====================

    /**
     * 将16进制ASCII码转换为整数
     */
    private static int hexAsciiToInt(byte[] asciiBytes) {
        // 将ASCII字节转换为对应的16进制字符
        /*StringBuilder hexBuilder = new StringBuilder();
        for (byte asciiByte : asciiBytes) {
            char asciiChar = (char) asciiByte;
            // ASCII字符 '0'-'9','A'-'F','a'-'f' 直接作为16进制字符
            hexBuilder.append(asciiChar);
        }

        String hexString = hexBuilder.toString();

        // 验证是否为有效的16进制字符串
        if (!hexString.matches("[0-9A-Fa-f]+")) {
            throw new IllegalArgumentException("无效的16进制ASCII码: " + hexString);
        }

        return Integer.parseInt(hexString, 16);*/
        String hexStr = new String(asciiBytes, StandardCharsets.US_ASCII);
        System.out.println("hexAsciiToInt 输入: '" + hexStr + "'");
        int result = Integer.parseInt(hexStr, 16);
        System.out.println("hexAsciiToInt 输出: " + result);
        return result;
    }

    /**
     * 解析重量值
     */
    private static double parseWeight(byte[] weightBytes) {
        // 重量值也是16进制ASCII码，转换为整数后再根据实际情况转换为重量值
        return hexAsciiToInt(weightBytes) / 100.0; // 假设精度为0.01
    }

    /**
     * 解析数据值
     */
    private static double parseDataValue(byte[] dataBytes) {
        return hexAsciiToInt(dataBytes) / 100.0; // 假设精度为0.01
    }

    /**
     * 解析仪器状态
     */
    private static String parseStatus(byte[] statusBytes) {
        int statusValue = hexAsciiToInt(statusBytes);
        return statusValue == 0 ? "非试验状态" : "试验状态";
    }

    /**
     * 解析日期时间
     */
    private static String parseDateTime(byte[] dateTimeBytes) {
        // 日期时间格式为年月日时分秒，每个2字节
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < dateTimeBytes.length; i += 2) {
            int value = hexAsciiToInt(new byte[]{dateTimeBytes[i], dateTimeBytes[i + 1]});
            sb.append(String.format("%02d", value));
            if (i == 1) sb.append("年");
            else if (i == 3) sb.append("月");
            else if (i == 5) sb.append("日");
            else if (i == 7) sb.append("时");
            else if (i == 9) sb.append("分");
        }
        sb.append("秒");
        return sb.toString();
    }

    /**
     * 解析材料类型
     */
    private static String parseMaterialType(byte[] materialBytes) {
        int typeValue = hexAsciiToInt(materialBytes);
        return "类型" + typeValue;
    }

    /**
     * 解析修正系数
     */
    private static double parseCorrectionFactor(byte[] factorBytes) {
        return hexAsciiToInt(factorBytes) / 100.0;
    }

    /**
     * 将十六进制字符串转换为字节数组
     * 输入格式示例: "02 55 00 00 32 43" 或 "025500003243"
     */
    public static byte[] hexStringToByteArray(String hexString) {
        // 移除所有空格
        String cleanedString = hexString.replaceAll("\\s+", "");

        // 检查字符串长度是否为偶数
        if (cleanedString.length() % 2 != 0) {
            throw new IllegalArgumentException("十六进制字符串长度必须为偶数");
        }

        byte[] data = new byte[cleanedString.length() / 2];
        for (int i = 0; i < cleanedString.length(); i += 2) {
            String byteString = cleanedString.substring(i, i + 2);
            data[i / 2] = (byte) Integer.parseInt(byteString, 16);
        }
        return data;
    }

    /**
     * 字节数组转换为十六进制字符串
     */
    private static String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }

    // ==================== 测试方法 ====================

    public static void main(String[] args) {
        // 方法1：使用程序生成正确的测试数据
        String correctTestData = generateNonTestDuctilityData();

        System.out.println("生成的测试数据: " + correctTestData);

        // 验证关键字段
        byte[] frame = hexStringToByteArray(correctTestData);

        // 数据3 (索引18-21)
        byte[] data3Bytes = Arrays.copyOfRange(frame, 18, 22);
        System.out.println("数据3: " + bytesToHexString(data3Bytes) + " -> '" +
                new String(data3Bytes) + "' -> " + hexAsciiToInt(data3Bytes));

        // 温度 (索引24-27)
        byte[] tempBytes = Arrays.copyOfRange(frame, 24, 28);
        System.out.println("温度: " + bytesToHexString(tempBytes) + " -> '" +
                new String(tempBytes) + "' -> " + hexAsciiToInt(tempBytes));

        // 完整解析
        System.out.println("\n=== 完整解析结果 ===");
        InstrumentData result = parseDataFrame(correctTestData);
        System.out.println(result);
    }


    public static String generateCorrectDuctilityData() {
        StringBuilder sb = new StringBuilder();

        // 帧头部分
        sb.append("02"); // 起始字节
        sb.append("55"); // 连接类型
        sb.append("0001"); // 设备类型 (延伸仪)
        sb.append("3330"); // 数据长度 (48字节)

        // 数据部分
        sb.append("30313233"); // 数据1: "0123" = 291
        sb.append("3035");     // 电机速度: "05" = 5
        sb.append("30313233"); // 数据2: "0123" = 291
        sb.append("3030");     // 空字节1
        sb.append("30313233"); // 数据3: "0123" = 291
        sb.append("3030");     // 空字节2
        sb.append("30313031"); // 温度: "0101" = 257
        sb.append("3031");     // 状态: "01" = 试验状态
        sb.append("323032343031313532333435"); // 日期: "202401152345"
        sb.append("3030303030303030"); // 空字节3
        sb.append("30313233"); // 验证码: "0123" = 291

        // 结束字节
        sb.append("0A");

        return sb.toString();
    }


    public static String generateNonTestDuctilityData() {
        StringBuilder sb = new StringBuilder();

        // 帧头部分
        sb.append("02"); // 起始字节
        sb.append("55"); // 连接类型
        sb.append("0001"); // 设备类型 (延伸仪)
        sb.append("3330"); // 数据长度 (48字节)

        // 数据部分 - 使用上次试验结果数据
        sb.append("30343536"); // 数据1: "0456" = 1110 mm
        sb.append("3033");     // 电机速度: "03" = 3 cm/min
        sb.append("30343536"); // 数据2: "0456" = 1110 mm
        sb.append("3030");     // 空字节1
        sb.append("30343536"); // 数据3: "0456" = 1110 mm
        sb.append("3030");     // 空字节2
        sb.append("30323032"); // 温度: "0202" = 514 × 0.1 = 51.4℃
        sb.append("3030");     // 状态: "00" = 非试验状态
        sb.append("323032343031313532333530"); // 日期: "202401152350"
        sb.append("3030303030303030"); // 空字节3
        sb.append("30343536"); // 验证码: "0456" = 1110

        // 结束字节
        sb.append("0A");

        return sb.toString();
    }

}